1   /*
2    * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.tools.jconsole.inspector;
27  
28  
29  import java.awt.BorderLayout;
30  import java.awt.Color;
31  import java.awt.Component;
32  import java.awt.Dimension;
33  import java.awt.event.ActionEvent;
34  import java.awt.event.ActionListener;
35  import java.io.IOException;
36  
37  import javax.management.IntrospectionException;
38  import javax.management.NotificationListener;
39  import javax.management.MBeanInfo;
40  import javax.management.InstanceNotFoundException;
41  import javax.management.ReflectionException;
42  import javax.management.MBeanAttributeInfo;
43  import javax.management.MBeanOperationInfo;
44  import javax.management.MBeanNotificationInfo;
45  import javax.management.Notification;
46  import javax.swing.BorderFactory;
47  import javax.swing.JButton;
48  import javax.swing.JOptionPane;
49  import javax.swing.JPanel;
50  import javax.swing.JScrollPane;
51  import javax.swing.JTextArea;
52  import javax.swing.SwingWorker;
53  import javax.swing.border.LineBorder;
54  import javax.swing.tree.DefaultMutableTreeNode;
55  import javax.swing.tree.DefaultTreeModel;
56  
57  import sun.tools.jconsole.*;
58  import sun.tools.jconsole.inspector.XNodeInfo.Type;
59  
60  import static sun.tools.jconsole.Resources.*;
61  
62  @SuppressWarnings("serial")
63  public class XSheet extends JPanel
64          implements ActionListener, NotificationListener {
65  
66      private JPanel mainPanel;
67      private JPanel southPanel;
68      // Node being currently displayed
69      private volatile DefaultMutableTreeNode currentNode;
70      // MBean being currently displayed
71      private volatile XMBean mbean;
72      // XMBeanAttributes container
73      private XMBeanAttributes mbeanAttributes;
74      // XMBeanOperations container
75      private XMBeanOperations mbeanOperations;
76      // XMBeanNotifications container
77      private XMBeanNotifications mbeanNotifications;
78      // XMBeanInfo container
79      private XMBeanInfo mbeanInfo;
80      // Refresh JButton (mbean attributes case)
81      private JButton refreshButton;
82      // Subscribe/Unsubscribe/Clear JButton (mbean notifications case)
83      private JButton clearButton,  subscribeButton,  unsubscribeButton;
84      // Reference to MBeans tab
85      private MBeansTab mbeansTab;
86  
87      public XSheet(MBeansTab mbeansTab) {
88          this.mbeansTab = mbeansTab;
89          setupScreen();
90      }
91  
92      public void dispose() {
93          clear();
94          XDataViewer.dispose(mbeansTab);
95          mbeanNotifications.dispose();
96      }
97  
98      private void setupScreen() {
99          setLayout(new BorderLayout());
100         setBorder(BorderFactory.createLineBorder(Color.GRAY));
101         // add main panel to XSheet
102         mainPanel = new JPanel();
103         mainPanel.setLayout(new BorderLayout());
104         add(mainPanel, BorderLayout.CENTER);
105         // add south panel to XSheet
106         southPanel = new JPanel();
107         add(southPanel, BorderLayout.SOUTH);
108         // create the refresh button
109         String refreshButtonKey = "MBeansTab.refreshAttributesButton";
110         refreshButton = new JButton(getText(refreshButtonKey));
111         refreshButton.setMnemonic(getMnemonicInt(refreshButtonKey));
112         refreshButton.setToolTipText(getText(refreshButtonKey + ".toolTip"));
113         refreshButton.addActionListener(this);
114         // create the clear button
115         String clearButtonKey = "MBeansTab.clearNotificationsButton";
116         clearButton = new JButton(getText(clearButtonKey));
117         clearButton.setMnemonic(getMnemonicInt(clearButtonKey));
118         clearButton.setToolTipText(getText(clearButtonKey + ".toolTip"));
119         clearButton.addActionListener(this);
120         // create the subscribe button
121         String subscribeButtonKey = "MBeansTab.subscribeNotificationsButton";
122         subscribeButton = new JButton(getText(subscribeButtonKey));
123         subscribeButton.setMnemonic(getMnemonicInt(subscribeButtonKey));
124         subscribeButton.setToolTipText(getText(subscribeButtonKey + ".toolTip"));
125         subscribeButton.addActionListener(this);
126         // create the unsubscribe button
127         String unsubscribeButtonKey = "MBeansTab.unsubscribeNotificationsButton";
128         unsubscribeButton = new JButton(getText(unsubscribeButtonKey));
129         unsubscribeButton.setMnemonic(getMnemonicInt(unsubscribeButtonKey));
130         unsubscribeButton.setToolTipText(getText(unsubscribeButtonKey + ".toolTip"));
131         unsubscribeButton.addActionListener(this);
132         // create XMBeanAttributes container
133         mbeanAttributes = new XMBeanAttributes(mbeansTab);
134         // create XMBeanOperations container
135         mbeanOperations = new XMBeanOperations(mbeansTab);
136         mbeanOperations.addOperationsListener(this);
137         // create XMBeanNotifications container
138         mbeanNotifications = new XMBeanNotifications();
139         mbeanNotifications.addNotificationsListener(this);
140         // create XMBeanInfo container
141         mbeanInfo = new XMBeanInfo();
142     }
143 
144     private boolean isSelectedNode(DefaultMutableTreeNode n, DefaultMutableTreeNode cn) {
145         return (cn == n);
146     }
147 
148     // Call on EDT
149     private void showErrorDialog(Object message, String title) {
150         new ThreadDialog(this, message, title, JOptionPane.ERROR_MESSAGE).run();
151     }
152 
153     public boolean isMBeanNode(DefaultMutableTreeNode node) {
154         Object userObject = node.getUserObject();
155         if (userObject instanceof XNodeInfo) {
156             XNodeInfo uo = (XNodeInfo) userObject;
157             return uo.getType().equals(Type.MBEAN);
158         }
159         return false;
160     }
161 
162     // Call on EDT
163     public synchronized void displayNode(DefaultMutableTreeNode node) {
164         clear();
165         displayEmptyNode();
166         if (node == null) {
167             return;
168         }
169         currentNode = node;
170         Object userObject = node.getUserObject();
171         if (userObject instanceof XNodeInfo) {
172             XNodeInfo uo = (XNodeInfo) userObject;
173             switch (uo.getType()) {
174                 case MBEAN:
175                     displayMBeanNode(node);
176                     break;
177                 case NONMBEAN:
178                     displayEmptyNode();
179                     break;
180                 case ATTRIBUTES:
181                     displayMBeanAttributesNode(node);
182                     break;
183                 case OPERATIONS:
184                     displayMBeanOperationsNode(node);
185                     break;
186                 case NOTIFICATIONS:
187                     displayMBeanNotificationsNode(node);
188                     break;
189                 case ATTRIBUTE:
190                 case OPERATION:
191                 case NOTIFICATION:
192                     displayMetadataNode(node);
193                     break;
194                 default:
195                     displayEmptyNode();
196                     break;
197             }
198         } else {
199             displayEmptyNode();
200         }
201     }
202 
203     // Call on EDT
204     private void displayMBeanNode(final DefaultMutableTreeNode node) {
205         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
206         if (!uo.getType().equals(Type.MBEAN)) {
207             return;
208         }
209         mbean = (XMBean) uo.getData();
210         SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
211             @Override
212             public MBeanInfo doInBackground() throws InstanceNotFoundException,
213                     IntrospectionException, ReflectionException, IOException {
214                 return mbean.getMBeanInfo();
215             }
216             @Override
217             protected void done() {
218                 try {
219                     MBeanInfo mbi = get();
220                     if (mbi != null) {
221                         if (!isSelectedNode(node, currentNode)) {
222                             return;
223                         }
224                         mbeanInfo.addMBeanInfo(mbean, mbi);
225                         invalidate();
226                         mainPanel.removeAll();
227                         mainPanel.add(mbeanInfo, BorderLayout.CENTER);
228                         southPanel.setVisible(false);
229                         southPanel.removeAll();
230                         validate();
231                         repaint();
232                     }
233                 } catch (Exception e) {
234                     Throwable t = Utils.getActualException(e);
235                     if (JConsole.isDebug()) {
236                         System.err.println("Couldn't get MBeanInfo for MBean [" +
237                                 mbean.getObjectName() + "]");
238                         t.printStackTrace();
239                     }
240                     showErrorDialog(t.toString(),
241                             Resources.getText("Problem displaying MBean"));
242                 }
243             }
244         };
245         sw.execute();
246     }
247 
248     // Call on EDT
249     private void displayMetadataNode(final DefaultMutableTreeNode node) {
250         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
251         final XMBeanInfo mbi = mbeanInfo;
252         switch (uo.getType()) {
253             case ATTRIBUTE:
254                 SwingWorker<MBeanAttributeInfo, Void> sw =
255                         new SwingWorker<MBeanAttributeInfo, Void>() {
256                             @Override
257                             public MBeanAttributeInfo doInBackground() {
258                                 Object attrData = uo.getData();
259                                 mbean = (XMBean) ((Object[]) attrData)[0];
260                                 MBeanAttributeInfo mbai =
261                                         (MBeanAttributeInfo) ((Object[]) attrData)[1];
262                                 mbeanAttributes.loadAttributes(mbean, new MBeanInfo(
263                                         null, null, new MBeanAttributeInfo[]{mbai},
264                                         null, null, null));
265                                 return mbai;
266                             }
267                             @Override
268                             protected void done() {
269                                 try {
270                                     MBeanAttributeInfo mbai = get();
271                                     if (!isSelectedNode(node, currentNode)) {
272                                         return;
273                                     }
274                                     invalidate();
275                                     mainPanel.removeAll();
276                                     JPanel attributePanel =
277                                             new JPanel(new BorderLayout());
278                                     JPanel attributeBorderPanel =
279                                             new JPanel(new BorderLayout());
280                                     attributeBorderPanel.setBorder(
281                                             BorderFactory.createTitledBorder(
282                                             Resources.getText("Attribute value")));
283                                     JPanel attributeValuePanel =
284                                             new JPanel(new BorderLayout());
285                                     attributeValuePanel.setBorder(
286                                             LineBorder.createGrayLineBorder());
287                                     attributeValuePanel.add(mbeanAttributes.getTableHeader(),
288                                             BorderLayout.PAGE_START);
289                                     attributeValuePanel.add(mbeanAttributes,
290                                             BorderLayout.CENTER);
291                                     attributeBorderPanel.add(attributeValuePanel,
292                                             BorderLayout.CENTER);
293                                     JPanel refreshButtonPanel = new JPanel();
294                                     refreshButtonPanel.add(refreshButton);
295                                     attributeBorderPanel.add(refreshButtonPanel,
296                                             BorderLayout.SOUTH);
297                                     refreshButton.setEnabled(true);
298                                     attributePanel.add(attributeBorderPanel,
299                                             BorderLayout.NORTH);
300                                     mbi.addMBeanAttributeInfo(mbai);
301                                     attributePanel.add(mbi, BorderLayout.CENTER);
302                                     mainPanel.add(attributePanel,
303                                             BorderLayout.CENTER);
304                                     southPanel.setVisible(false);
305                                     southPanel.removeAll();
306                                     validate();
307                                     repaint();
308                                 } catch (Exception e) {
309                                     Throwable t = Utils.getActualException(e);
310                                     if (JConsole.isDebug()) {
311                                         System.err.println("Problem displaying MBean " +
312                                                 "attribute for MBean [" +
313                                                 mbean.getObjectName() + "]");
314                                         t.printStackTrace();
315                                     }
316                                     showErrorDialog(t.toString(),
317                                             Resources.getText("Problem displaying MBean"));
318                                 }
319                             }
320                         };
321                 sw.execute();
322                 break;
323             case OPERATION:
324                 Object operData = uo.getData();
325                 mbean = (XMBean) ((Object[]) operData)[0];
326                 MBeanOperationInfo mboi =
327                         (MBeanOperationInfo) ((Object[]) operData)[1];
328                 mbeanOperations.loadOperations(mbean,
329                         new MBeanInfo(null, null, null, null,
330                         new MBeanOperationInfo[]{mboi}, null));
331                 invalidate();
332                 mainPanel.removeAll();
333                 JPanel operationPanel = new JPanel(new BorderLayout());
334                 JPanel operationBorderPanel = new JPanel(new BorderLayout());
335                 operationBorderPanel.setBorder(BorderFactory.createTitledBorder(
336                         Resources.getText("Operation invocation")));
337                 operationBorderPanel.add(new JScrollPane(mbeanOperations));
338                 operationPanel.add(operationBorderPanel, BorderLayout.NORTH);
339                 mbi.addMBeanOperationInfo(mboi);
340                 operationPanel.add(mbi, BorderLayout.CENTER);
341                 mainPanel.add(operationPanel, BorderLayout.CENTER);
342                 southPanel.setVisible(false);
343                 southPanel.removeAll();
344                 validate();
345                 repaint();
346                 break;
347             case NOTIFICATION:
348                 Object notifData = uo.getData();
349                 invalidate();
350                 mainPanel.removeAll();
351                 mbi.addMBeanNotificationInfo((MBeanNotificationInfo) notifData);
352                 mainPanel.add(mbi, BorderLayout.CENTER);
353                 southPanel.setVisible(false);
354                 southPanel.removeAll();
355                 validate();
356                 repaint();
357                 break;
358         }
359     }
360 
361     // Call on EDT
362     private void displayMBeanAttributesNode(final DefaultMutableTreeNode node) {
363         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
364         if (!uo.getType().equals(Type.ATTRIBUTES)) {
365             return;
366         }
367         mbean = (XMBean) uo.getData();
368         final XMBean xmb = mbean;
369         SwingWorker<MBeanInfo,Void> sw = new SwingWorker<MBeanInfo,Void>() {
370             @Override
371             public MBeanInfo doInBackground() throws InstanceNotFoundException,
372                     IntrospectionException, ReflectionException, IOException {
373                 MBeanInfo mbi = xmb.getMBeanInfo();
374                 return mbi;
375             }
376             @Override
377             protected void done() {
378                 try {
379                     MBeanInfo mbi = get();
380                     if (mbi != null && mbi.getAttributes() != null &&
381                             mbi.getAttributes().length > 0) {
382 
383                         mbeanAttributes.loadAttributes(xmb, mbi);
384 
385                         if (!isSelectedNode(node, currentNode)) {
386                             return;
387                         }
388                         invalidate();
389                         mainPanel.removeAll();
390                         JPanel borderPanel = new JPanel(new BorderLayout());
391                         borderPanel.setBorder(BorderFactory.createTitledBorder(
392                                 Resources.getText("Attribute values")));
393                         borderPanel.add(new JScrollPane(mbeanAttributes));
394                         mainPanel.add(borderPanel, BorderLayout.CENTER);
395                         // add the refresh button to the south panel
396                         southPanel.removeAll();
397                         southPanel.add(refreshButton, BorderLayout.SOUTH);
398                         southPanel.setVisible(true);
399                         refreshButton.setEnabled(true);
400                         validate();
401                         repaint();
402                     }
403                 } catch (Exception e) {
404                     Throwable t = Utils.getActualException(e);
405                     if (JConsole.isDebug()) {
406                         System.err.println("Problem displaying MBean " +
407                                 "attributes for MBean [" +
408                                 mbean.getObjectName() + "]");
409                         t.printStackTrace();
410                     }
411                     showErrorDialog(t.toString(),
412                             Resources.getText("Problem displaying MBean"));
413                 }
414             }
415         };
416         sw.execute();
417     }
418 
419     // Call on EDT
420     private void displayMBeanOperationsNode(final DefaultMutableTreeNode node) {
421         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
422         if (!uo.getType().equals(Type.OPERATIONS)) {
423             return;
424         }
425         mbean = (XMBean) uo.getData();
426         SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
427             @Override
428             public MBeanInfo doInBackground() throws InstanceNotFoundException,
429                     IntrospectionException, ReflectionException, IOException {
430                 return mbean.getMBeanInfo();
431             }
432             @Override
433             protected void done() {
434                 try {
435                     MBeanInfo mbi = get();
436                     if (mbi != null) {
437                         if (!isSelectedNode(node, currentNode)) {
438                             return;
439                         }
440                         mbeanOperations.loadOperations(mbean, mbi);
441                         invalidate();
442                         mainPanel.removeAll();
443                         JPanel borderPanel = new JPanel(new BorderLayout());
444                         borderPanel.setBorder(BorderFactory.createTitledBorder(
445                                 Resources.getText("Operation invocation")));
446                         borderPanel.add(new JScrollPane(mbeanOperations));
447                         mainPanel.add(borderPanel, BorderLayout.CENTER);
448                         southPanel.setVisible(false);
449                         southPanel.removeAll();
450                         validate();
451                         repaint();
452                     }
453                 } catch (Exception e) {
454                     Throwable t = Utils.getActualException(e);
455                     if (JConsole.isDebug()) {
456                         System.err.println("Problem displaying MBean " +
457                                 "operations for MBean [" +
458                                 mbean.getObjectName() + "]");
459                         t.printStackTrace();
460                     }
461                     showErrorDialog(t.toString(),
462                             Resources.getText("Problem displaying MBean"));
463                 }
464             }
465         };
466         sw.execute();
467     }
468 
469     // Call on EDT
470     private void displayMBeanNotificationsNode(DefaultMutableTreeNode node) {
471         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
472         if (!uo.getType().equals(Type.NOTIFICATIONS)) {
473             return;
474         }
475         mbean = (XMBean) uo.getData();
476         mbeanNotifications.loadNotifications(mbean);
477         updateNotifications();
478         invalidate();
479         mainPanel.removeAll();
480         JPanel borderPanel = new JPanel(new BorderLayout());
481         borderPanel.setBorder(BorderFactory.createTitledBorder(
482                 Resources.getText("Notification buffer")));
483         borderPanel.add(new JScrollPane(mbeanNotifications));
484         mainPanel.add(borderPanel, BorderLayout.CENTER);
485         // add the subscribe/unsubscribe/clear buttons to the south panel
486         southPanel.removeAll();
487         southPanel.add(subscribeButton, BorderLayout.WEST);
488         southPanel.add(unsubscribeButton, BorderLayout.CENTER);
489         southPanel.add(clearButton, BorderLayout.EAST);
490         southPanel.setVisible(true);
491         subscribeButton.setEnabled(true);
492         unsubscribeButton.setEnabled(true);
493         clearButton.setEnabled(true);
494         validate();
495         repaint();
496     }
497 
498     // Call on EDT
499     private void displayEmptyNode() {
500         invalidate();
501         mainPanel.removeAll();
502         southPanel.removeAll();
503         validate();
504         repaint();
505     }
506 
507     /**
508      * Subscribe button action.
509      */
510     private void registerListener() {
511         new SwingWorker<Void, Void>() {
512             @Override
513             public Void doInBackground()
514                     throws InstanceNotFoundException, IOException {
515                 mbeanNotifications.registerListener(currentNode);
516                 return null;
517             }
518             @Override
519             protected void done() {
520                 try {
521                     get();
522                     updateNotifications();
523                     validate();
524                 } catch (Exception e) {
525                     Throwable t = Utils.getActualException(e);
526                     if (JConsole.isDebug()) {
527                         System.err.println("Problem adding listener");
528                         t.printStackTrace();
529                     }
530                     showErrorDialog(t.getMessage(),
531                             Resources.getText("Problem adding listener"));
532                 }
533             }
534         }.execute();
535     }
536 
537     /**
538      * Unsubscribe button action.
539      */
540     private void unregisterListener() {
541         new SwingWorker<Boolean, Void>() {
542             @Override
543             public Boolean doInBackground() {
544                 return mbeanNotifications.unregisterListener(currentNode);
545             }
546             @Override
547             protected void done() {
548                 try {
549                     if (get()) {
550                         updateNotifications();
551                         validate();
552                     }
553                 } catch (Exception e) {
554                     Throwable t = Utils.getActualException(e);
555                     if (JConsole.isDebug()) {
556                         System.err.println("Problem removing listener");
557                         t.printStackTrace();
558                     }
559                     showErrorDialog(t.getMessage(),
560                             Resources.getText("Problem removing listener"));
561                 }
562             }
563         }.execute();
564     }
565 
566     /**
567      * Refresh button action.
568      */
569     private void refreshAttributes() {
570         mbeanAttributes.refreshAttributes();
571     }
572 
573     // Call on EDT
574     private void updateNotifications() {
575         if (mbeanNotifications.isListenerRegistered(mbean)) {
576             long received = mbeanNotifications.getReceivedNotifications(mbean);
577             updateReceivedNotifications(currentNode, received, false);
578         } else {
579             clearNotifications();
580         }
581     }
582 
583     /**
584      * Update notification node label in MBean tree: "Notifications[received]".
585      */
586     // Call on EDT
587     private void updateReceivedNotifications(
588             DefaultMutableTreeNode emitter, long received, boolean bold) {
589         String text = Resources.getText("Notifications") + "[" + received + "]";
590         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) mbeansTab.getTree().getLastSelectedPathComponent();
591         if (bold && emitter != selectedNode) {
592             text = "<html><b>" + text + "</b></html>";
593         }
594         updateNotificationsNodeLabel(emitter, text);
595     }
596 
597     /**
598      * Update notification node label in MBean tree: "Notifications".
599      */
600     // Call on EDT
601     private void clearNotifications() {
602         updateNotificationsNodeLabel(currentNode,
603                 Resources.getText("Notifications"));
604     }
605 
606     /**
607      * Update notification node label in MBean tree: "Notifications[0]".
608      */
609     // Call on EDT
610     private void clearNotifications0() {
611         updateNotificationsNodeLabel(currentNode,
612                 Resources.getText("Notifications") + "[0]");
613     }
614 
615     /**
616      * Update the label of the supplied MBean tree node.
617      */
618     // Call on EDT
619     private void updateNotificationsNodeLabel(
620             DefaultMutableTreeNode node, String label) {
621         synchronized (mbeansTab.getTree()) {
622             invalidate();
623             XNodeInfo oldUserObject = (XNodeInfo) node.getUserObject();
624             XNodeInfo newUserObject = new XNodeInfo(
625                     oldUserObject.getType(), oldUserObject.getData(),
626                     label, oldUserObject.getToolTipText());
627             node.setUserObject(newUserObject);
628             DefaultTreeModel model =
629                     (DefaultTreeModel) mbeansTab.getTree().getModel();
630             model.nodeChanged(node);
631             validate();
632             repaint();
633         }
634     }
635 
636     /**
637      * Clear button action.
638      */
639     // Call on EDT
640     private void clearCurrentNotifications() {
641         mbeanNotifications.clearCurrentNotifications();
642         if (mbeanNotifications.isListenerRegistered(mbean)) {
643             // Update notifs in MBean tree "Notifications[0]".
644             //
645             // Notification buffer has been cleared with a listener been
646             // registered so add "[0]" at the end of the node label.
647             //
648             clearNotifications0();
649         } else {
650             // Update notifs in MBean tree "Notifications".
651             //
652             // Notification buffer has been cleared without a listener been
653             // registered so don't add "[0]" at the end of the node label.
654             //
655             clearNotifications();
656         }
657     }
658 
659     // Call on EDT
660     private void clear() {
661         mbeanAttributes.stopCellEditing();
662         mbeanAttributes.emptyTable();
663         mbeanAttributes.removeAttributes();
664         mbeanOperations.removeOperations();
665         mbeanNotifications.stopCellEditing();
666         mbeanNotifications.emptyTable();
667         mbeanNotifications.disableNotifications();
668         mbean = null;
669         currentNode = null;
670     }
671 
672     /**
673      * Notification listener: handles asynchronous reception
674      * of MBean operation results and MBean notifications.
675      */
676     // Call on EDT
677     public void handleNotification(Notification e, Object handback) {
678         // Operation result
679         if (e.getType().equals(XOperations.OPERATION_INVOCATION_EVENT)) {
680             final Object message;
681             if (handback == null) {
682                 JTextArea textArea = new JTextArea("null");
683                 textArea.setEditable(false);
684                 textArea.setEnabled(true);
685                 textArea.setRows(textArea.getLineCount());
686                 message = textArea;
687             } else {
688                 Component comp = mbeansTab.getDataViewer().
689                         createOperationViewer(handback, mbean);
690                 if (comp == null) {
691                     JTextArea textArea = new JTextArea(handback.toString());
692                     textArea.setEditable(false);
693                     textArea.setEnabled(true);
694                     textArea.setRows(textArea.getLineCount());
695                     JScrollPane scrollPane = new JScrollPane(textArea);
696                     Dimension d = scrollPane.getPreferredSize();
697                     if (d.getWidth() > 400 || d.getHeight() > 250) {
698                         scrollPane.setPreferredSize(new Dimension(400, 250));
699                     }
700                     message = scrollPane;
701                 } else {
702                     if (!(comp instanceof JScrollPane)) {
703                         comp = new JScrollPane(comp);
704                     }
705                     Dimension d = comp.getPreferredSize();
706                     if (d.getWidth() > 400 || d.getHeight() > 250) {
707                         comp.setPreferredSize(new Dimension(400, 250));
708                     }
709                     message = comp;
710                 }
711             }
712             new ThreadDialog(
713                     (Component) e.getSource(),
714                     message,
715                     Resources.getText("Operation return value"),
716                     JOptionPane.INFORMATION_MESSAGE).run();
717         } // Got notification
718         else if (e.getType().equals(
719                 XMBeanNotifications.NOTIFICATION_RECEIVED_EVENT)) {
720             DefaultMutableTreeNode emitter = (DefaultMutableTreeNode) handback;
721             Long received = (Long) e.getUserData();
722             updateReceivedNotifications(emitter, received.longValue(), true);
723         }
724     }
725 
726     /**
727      * Action listener: handles actions in panel buttons
728      */
729     // Call on EDT
730     public void actionPerformed(ActionEvent e) {
731         if (e.getSource() instanceof JButton) {
732             JButton button = (JButton) e.getSource();
733             // Refresh button
734             if (button == refreshButton) {
735                 refreshAttributes();
736                 return;
737             }
738             // Clear button
739             if (button == clearButton) {
740                 clearCurrentNotifications();
741                 return;
742             }
743             // Subscribe button
744             if (button == subscribeButton) {
745                 registerListener();
746                 return;
747             }
748             // Unsubscribe button
749             if (button == unsubscribeButton) {
750                 unregisterListener();
751                 return;
752             }
753         }
754     }
755 }